Spring DAO


1. 前言

本文是<<精通Spring 4.x 企业应用开发实战>>学习笔记, 以便自己查阅.

2. 概述

近几年持久化技术领域异常喧嚣,各种框架雨后春笋般地冒出,Sun也连接不断地颁布几个持久化规范.Spring对多个持久化技术提供了集成的支持,包括 Hibernate, iBatis, JDO, JPA, TopLink, 此外, 还通过Spring JDBC框架对JDBC API进行简化. Spring面向DAO制定了一个通用的异常体系, 屏蔽具体持久化技术的异常, 使业务层和具体的持久化技术达到解耦. 此外, Spring 提供了模板类简化各种持久化技术的使用. 通用的异常体系及模板类是Spring整合各种五花八门持久化技术的不二法门, Spring不但借此实现了对多种持久化技术的整合, 还可以不费吹灰之力整合潜在的各种持久化框架, 体现了”开-闭原则”的经典应用.

3. Spring的DAO理念

DAO(Data Access Object)是用于访问数据的对象, 虽然我们在大多数情况下, 将数据保存在数据库中, 但这并不是唯一的选择, 你也可以将数据存储到文件中或LDAP中. DAO不但屏蔽了数据存储的最终介质的不同, 也屏蔽了具体的实现技术的不同.
早期, JDBC是访问数据库的主流选择,近几年,数据持久技术获得了长足的发展,Hibernate,iBatis,JPA,JDO成为持久层中争放异彩的实现技术.只要为数据访问定义好DAO接口,并使用具体的技术实现DAO接口的功能,你就可以在不同的实现技术间平滑的切换.
DAO

图1 业务层通过DAO接口访问数据

在UserDao中定义访问User数据对象的接口方法,业务层通过UserDao操作数据,并使用具体持久技术实现UserDao接口方法,这样业务层和具体持久化技术就实现了解耦.
提供DAO层的抽象可以带来一些好处,首先,我们可以很容易地构造模拟对象,方便单元测试的开展,其次在使用切面时,我们有更多的选择:既可以使用JDK动态代理也可以使用CGLib动态代理.
Spring本质上希望以统一的方式整合底层的持久化技术:以统一的方式进行调用及事务管理,避免让具体的实现侵入到业务层的代码中.由于每个持久化实现技术都有各自的异常体系,所以Spring提供了统一的异常体系,使不同异常体系的阻抗得以弥消,方便定义出和具体实现技术无关的DAO接口,以及整合到相同的事务管理体系中.
DAO

图2 统一的异常体系

4. 统一的异常体系

统一的异常体系是整合不同的持久化实现技术的关键,Spring提供了一套和实现技术无关的,面向于DAO层次语义的异常体系,并通过转换器将不同的持久化技术异常转换成Spring的异常.

4.1 Spring的DAO异常体系

在很多正统API或框架中, 检查型异常被过多的使用, 以至在使用API时, 代码里充斥着大量的try/catch样板式的代码.在很多情况下, 除了在 try/catch中记录异常信息以外, 我们并没有做多少实质性的工作. 引发异常的问题往往是不可恢复的, 如数据连接失败, SQL语句存在语法错误, 强制捕捉的检查型异常除了限制开发人员的自由度以外, 并没有提供什么有意义的作用. 因此, Spring的异常体系都是建立在运行期异常的基础上, 开发者可以根据需要捕捉感兴趣的异常.
JDK很多API之所以难用, 一个很大的原因就是检查型异常的泛滥, 如JavaMail, EJB以及JDBC等等, 使用这些API, 一堆堆异常处理的代码喧宾夺主式地侵入业务代码中, 破坏了代码的整洁和优雅.
Spring在org.springframework.dao包中提供了一套完备优雅的DAO异常体系, 这些异常都继承于DataAccessException, 而DataAccessException本身又继承于 NestedRuntimeException,NestedRuntimeException异常以嵌套的方式封装了源异常.因为虽然不同持久化技术的特定异常被转换到Spring的DAO异常体系中, 原始的异常信息并不会丢失, 只要你愿意, 就可以方便地通过getCause()方法获取原始的异常信息.
Spring的DAO异常体系并不和具体的实现技术相关,它从DAO概念的抽象层面定义了异常的目录树.在所有的持久化框架中,我们并没有发现拥有如此丰富语义异常体系的框架,Spring这种设计无疑是独具匠心的,它使得开发人员关注某一特定语义的异常变得容易.在JDBC中的SQLException 中,你必须通过异常的getErrorCode()或getSQLState()获取错误代码,直接根据这些代码判断是错误的类型,这种过于底层的API 不但带来了代码编写上的难度,而且也使代码的移植变得困难,因为getErrorCode()是数据库相关的.
Spring以分类手法建立了异常分类目录,对于大部分应用来说,这个异常分类目录对异常类型的划分具有适当的颗粒度.一方面,使开发者从底层细如针麻的技术细节中脱身出来,另一方面,可以从这个语义丰富的异常体系中选择感兴趣的异常加以处理.上面图2中列出了那些位于Spring DAO异常体系第一层次的异常类,每个异常类下还可能拥有众多的子异常.

5. 参考链接

Spring DAO层的设计思想
<<精通Spring 4.x 企业应用开发实战>>

谢谢你请我吃糖果!